////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//   Software       :                                                         //
//   Layer          : SRC                                                     //
//   Package        :                                                         //
//   Component      :                                                         //
//                                                                            //
//   File           : CGlobal.cxx                                            //
//   Author         : RSO ( Rafael Sotomayor Brûlé )                          //
//   EMail          : rsotomayor@savtec.cl                                    //
//   Type           : C++ Source                                              //
//   Usage          :                                                         //
//   Purpose        : Implementación de ATD y Funciones globales              //
//                                                                            //
//                                                                            //
//   who when        what                                                     //
//   ~~~ ~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//   RSO 09-10-2010  Creation                                                 //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <map> 
#include <string>
#include <curl/curl.h>
#include <fstream>  

#include "mylib/errlog.h"
#include "mylib/utilconf.h"
#include "cglobal.h"
#include "cconfig.h"
#include "cxml.h"
#include "myutil.h"
#include "cdatabase.h"

extern CConfig    *config_g;
extern CDataBase  *database_g;
extern MyUtil     *myUtil_g;

CGlobal* CGlobal::pCGlobal_a=NULL;


CGlobal::CGlobal() {
  isOn_a = 1 ;
  pCGlobal_a = this;
  pthread_mutex_init (&mutQueue_a, NULL); 
  pthread_mutex_init (&mutEstadoServidor_a, NULL); 

  pthread_mutex_init (&mutexEstado_a, NULL); 

  sem_init(&jobQueueCont_a,0,0);

  estado_a = estadoAnterior_a = e_IDLE ;
  flagEstadoServidor_a = flagEstadoServidorAnterior_a = e_CONNECTFAIL  ;

}

CGlobal::~CGlobal() {
  pthread_mutex_destroy(&mutEstadoServidor_a); 
  pthread_mutex_destroy(&mutQueue_a); 
  pthread_mutex_destroy(&mutexEstado_a);
}


void CGlobal::myhandleSignal(int SignalNumber_p) {
  int counter ;

  switch (SignalNumber_p) {
    case SIGTERM:
    case SIGINT:
      errLog::LOGERR((errLog::SEVERE,(char *) "PROCESO TERMINA NORMALMENTE POR SIGNAL [%d] [%s]\n",SignalNumber_p,GetSignalName(SignalNumber_p)));
      pCGlobal_a->isOn_a = 0 ;
      counter = 0 ;
      while ( counter++ < 3 ) {
        errLog::LOGERR((errLog::INFO,(char *) "WAITING TO QUIT  [%d] \n",counter));
        sleep(1);
      }
      break;
    case SIGSEGV:
    case SIGFPE:
      errLog::LOGERR((errLog::FATAL,(char *)"PROCESO TERMINA POR SIGNAL [%d] [%s]\n",SignalNumber_p,GetSignalName(SignalNumber_p)));
      counter = 0 ;
      while ( counter++ < 3 ) {
        errLog::LOGERR((errLog::INFO,(char *) "WAITING TO QUIT  [%d] \n",counter));
        sleep(1);
      }
      exit(EXIT_FAILURE);
    default:
      errLog::LOGERR((errLog::SEVERE,(char *)"PROCESO CAPTURA SIGNAL [%d] [%s]\n",SignalNumber_p,GetSignalName(SignalNumber_p)));
      break;
  }   
}


int CGlobal::startGeoServicio() {
  int retval=-1;

  string dummy ;

  if ( config_g->getParametro("latitud","geo",dummy) == 0 ) {
    dataGeo_a.latitud  = atof(dummy.data());
  } else {
    dataGeo_a.latitud  = -70.35 ;
  }

  if ( config_g->getParametro("longitud","geo",dummy) == 0 ) {
    dataGeo_a.longitud  = atof(dummy.data());
  } else {
    dataGeo_a.longitud  = -30.35 ;
  }

  if ( config_g->getParametro("altura","geo",dummy) == 0 ) {
    dataGeo_a.altura  = atof(dummy.data());
  } else {
    dataGeo_a.altura  = 0.0 ;
  }

  if ( config_g->getParametro("velocidad","geo",dummy) == 0 ) {
    dataGeo_a.velocidad  = atof(dummy.data());
  } else {
    dataGeo_a.velocidad  = 0.0 ;
  }

  if ( config_g->getParametro("rumbo","geo",dummy) == 0 ) {
    dataGeo_a.rumbo  = atof(dummy.data());
  } else {
    dataGeo_a.rumbo  = 0.0 ;
  }

  retval = 0;

  return retval;
} 

void CGlobal::startTareas() {

  errLog::LOGERR((errLog::INFO,(char *)"Iniciando Tareas CPost\n")); 
  int s;  
  pthread_attr_t *attrp; 
  pthread_attr_t atributos;
  pthread_t      pThreadId; 
  
  attrp = &atributos; 
  if (pthread_attr_init(&atributos) != 0) {
    errLog::LOGERR((errLog::SEVERE,(char *)"Thread ID [threadArgsLed]:En creación de estructura de atributos.\n"));    
    exit(EXIT_FAILURE);
  }
  if (pthread_attr_setdetachstate(&atributos,  PTHREAD_CREATE_DETACHED) != 0) {
    errLog::LOGERR((errLog::SEVERE,(char *)"Thread ID [threadArgsLed]:En el cambio de atributos.\n"));                  
    exit(EXIT_FAILURE);
  }  


  if ( (pthread_create(&pThreadId,&atributos,procesaTrabajosTask, NULL)) != 0 ) {
    errLog::LOGERR((errLog::SEVERE,(char *)"Error creando Thread [pThreadProcesaTrabajosTask_a]\n"));
    exit(EXIT_FAILURE);          
  }  

  
  if (attrp != NULL) {
    s = pthread_attr_destroy(attrp);
    if (s != 0) {
      errLog::LOGERR((errLog::SEVERE,(char *)"Error [pthread_attr_destroy]\n")); 
    }
  }  


}

int CGlobal::readGeoData() {
  int retval=-1;
  string dummy ;

  if ( config_g->getParametro("latitud","geo",dummy) == 0 ) {
    dataGeo_a.latitud  = atof(dummy.data());
  } else {
    dataGeo_a.latitud  = -70.35 ;
  }

  if ( config_g->getParametro("longitud","geo",dummy) == 0 ) {
    dataGeo_a.longitud  = atof(dummy.data());
  } else {
    dataGeo_a.longitud  = -30.35 ;
  }

  if ( config_g->getParametro("altura","geo",dummy) == 0 ) {
    dataGeo_a.altura  = atof(dummy.data());
  } else {
    dataGeo_a.altura  = 0.0 ;
  }

  if ( config_g->getParametro("velocidad","geo",dummy) == 0 ) {
    dataGeo_a.velocidad  = atof(dummy.data());
  } else {
    dataGeo_a.velocidad  = 0.0 ;
  }

  if ( config_g->getParametro("rumbo","geo",dummy) == 0 ) {
    dataGeo_a.rumbo  = atof(dummy.data());
  } else {
    dataGeo_a.rumbo  = 0.0 ;
  }

  retval = 0;

  return retval;
}

void *CGlobal::procesaTrabajosTask(void *p) {
  int counter=0;

  CGlobal::tTransaccion  data;
  while ( pCGlobal_a->isOn_a ) {
    sem_wait(&pCGlobal_a->jobQueueCont_a);

    while ( !pCGlobal_a->queueTask_a.empty() ) {
      data = pCGlobal_a->queueTask_a.front();
      errLog::LOGERR((errLog::TRACE,"Tamano de la cola %d\n",pCGlobal_a->queueTask_a.size()));
      pthread_mutex_lock (&pCGlobal_a->mutQueue_a); 
      pCGlobal_a->queueTask_a.pop();
      pthread_mutex_unlock (&pCGlobal_a->mutQueue_a);
      database_g->guardarTransaccion(data); 
    }

    errLog::LOGERR((errLog::TRACE,"Procesa Trabajos Task %d\n",counter++));
  }

  return NULL;
}


int CGlobal::send2Server(tTransaccion transaccion_p) {
  int     sockfd ;
  int     timeout=5;

  errLog::LOGERR((errLog::TRACE,"Registrando Acceso idusuario %s\n",transaccion_p.idusuario.data()));

  char buffer[1024];
  string dummy ;

  map<string, string> mypost;

  mypost.insert(pair<string, string>("wsname", "registraAcceso"));
  mypost.insert(pair<string, string>("idevento", transaccion_p.idevento));
  mypost.insert(pair<string, string>("idtipoevento", transaccion_p.idtipoevento));

  mypost.insert(pair<string, string>("idacceso", transaccion_p.idacceso));
  mypost.insert(pair<string, string>("idmodulo", transaccion_p.idmodulo));
  mypost.insert(pair<string, string>("idmovil" , transaccion_p.idmovil));
  mypost.insert(pair<string, string>("idresultado" , transaccion_p.idresultado));

  sprintf(buffer,"%d",transaccion_p.idfinger);
  dummy = buffer; 
  mypost.insert(pair<string, string>("idfinger" ,dummy));

  sprintf(buffer,"%d",transaccion_p.score);
  dummy = buffer; 
  mypost.insert(pair<string, string>("scorehuella" ,dummy));


  sprintf(buffer,"%f",transaccion_p.geo.latitud);
  dummy = buffer; 
  mypost.insert(pair<string, string>("latitud" ,dummy));

  sprintf(buffer,"%f",  transaccion_p.geo.longitud);
  dummy = buffer; 
  mypost.insert(pair<string, string>("longitud",dummy));

  sprintf(buffer,"%f",transaccion_p.geo.altura);
  dummy = buffer; 
  mypost.insert(pair<string, string>("altura",dummy));

  sprintf(buffer,"%f", transaccion_p.geo.velocidad);
  dummy = buffer; 
  mypost.insert(pair<string, string>("velocidad",dummy));

  sprintf(buffer,"%f",transaccion_p.geo.rumbo);
  dummy = buffer; 
  mypost.insert(pair<string, string>("rumbo", dummy));

  sprintf(buffer,"%ld",transaccion_p.geo.ts);
  dummy = buffer; 
  mypost.insert(pair<string, string>("ts", dummy));

  mypost.insert(pair<string, string>("idusuario", transaccion_p.idusuario));

  mypost.insert(pair<string, string>("idestado", transaccion_p.idestado));
  mypost.insert(pair<string, string>("opcion", transaccion_p.opcion));

  sprintf(buffer,"%d",transaccion_p.score);
  dummy = buffer; 
  mypost.insert(pair<string, string>("score", dummy));

  string urlpost ;
  string response;
  
  urlpost = config_g->serverHostName_a ;
  urlpost = urlpost + config_g->serverUrl_a ;
  
  CGlobal::tEstadoServidor estadoServidor ;
  estadoServidor = CGlobal::e_CONNECTFAIL ;

  errLog::LOGERR((errLog::TRACE,"Verificando estado Servidor\n"));
  if ( (sockfd = connect_w_to(config_g->serverAddress_a.data(),config_g->serverPort_a,timeout) ) > 0  ) {  
    close(sockfd);
    errLog::LOGERR((errLog::TRACE,"Envia Transaccion Server %s\n",urlpost.data()));  
  
    myUtil_g->wpost(urlpost.data(),mypost,response);
    errLog::LOGERR((errLog::TRACE,"Response XML: %s\n",response.data()));
    string result;
    CXML *myxml;
    myxml = new CXML();
    myxml->parseResult(response,result) ;
    errLog::LOGERR((errLog::TRACE,"Result: %s\n",result.data()));
    if ( result == "OK" ) {
      estadoServidor = CGlobal::e_POSTOK ; 
    } else {
      estadoServidor = CGlobal::e_POSTFAIL ; 
    }
  } else {
    errLog::LOGERR((errLog::WARN,"*** NO puede conectar a servidor %s:%d ***\n",
                            config_g->serverAddress_a.data(),config_g->serverPort_a));
    estadoServidor = CGlobal::e_CONNECTFAIL ; 
  }


  pthread_mutex_lock (&pCGlobal_a->mutEstadoServidor_a); 
  pCGlobal_a->flagEstadoServidorAnterior_a = pCGlobal_a->flagEstadoServidor_a ;
  pCGlobal_a->flagEstadoServidor_a         = estadoServidor; 
  pthread_mutex_unlock (&pCGlobal_a->mutEstadoServidor_a); 

  if ( pCGlobal_a->flagEstadoServidorAnterior_a != pCGlobal_a->flagEstadoServidor_a ) {
    pCGlobal_a->notificaFalla(1,"SERVER");
  }


  return ( estadoServidor == CGlobal::e_POSTOK ) ? 0 : -1 ;
} 




char *CGlobal::getStrEstado(eEstado estado_p) {
  string estado;

  switch ( estado_p) {
    case e_IDLE:
      estado = "e_IDLE";
      break;
    case e_CONFIG:
      estado = "e_CONFIG";
      break;
    default:
      estado = "e_UNKNOWN";
      break;
  }
  return (char *) estado.data();
  
}

void CGlobal::setEstado(eEstado estado_p) {

  pthread_mutex_lock(&mutexEstado_a);
  tCambioEstado_a = time(NULL);
  estadoAnterior_a = estado_a ;
  estado_a = estado_p ;
  pthread_mutex_unlock(&mutexEstado_a);
  errLog::LOGERR((errLog::TRACE,"Cambia Estado %s => %s\n",getStrEstado(estadoAnterior_a),getStrEstado(estado_a)));

}






